/*
	Copyright (c) 2005 Peter Moore

	Permission is hereby granted, free of charge, to any person obtaining a copy of
	this software and associated documentation files (the "Software"), to deal in the
	Software without restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
	Software, and to permit persons to whom the Software is furnished to do so,
	subject to the following conditions:

	The above copyright notice and this permission notice shall be included,
	unmodified, in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
	FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
	COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
	AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
	WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef __DME_H__
#define __DME_H__

#include <map>

#if defined(WIN32) && defined(_USRDLL)
#	define DME_EXPORT __declspec(dllexport)
#else
#	define DME_EXPORT
#endif

namespace DarkMatter
{
	typedef void (*ThreadProc)(void*);
	enum VertexType { VERTEX_TYPE_VERTEX, VERTEX_TYPE_TEXTURE, VERTEX_TYPE_COLOR };
	enum PrimitiveType { PRIMITIVE_TYPE_TRIANGLE, PRIMITIVE_TYPE_QUAD };
	struct Vertex { VertexType vtype; float x, y, z, q; };

	// Effective C++ 3rd Edition by Scott Meyers, page 37
	class DME_EXPORT Uncopyable
	{
		protected:
			Uncopyable();
			~Uncopyable();

		private:
			Uncopyable(const Uncopyable&);
			Uncopyable& operator=(const Uncopyable&);
	};

	class EngineResource: private Uncopyable
	{
		friend class Engine;

		protected:
			EngineResource();
			virtual ~EngineResource();
			virtual void Delete() = 0;
	};

	class DME_EXPORT Engine: private Uncopyable
	{
		friend DME_EXPORT Engine* InitializeEngine();
		friend class Screen_Impl;
		friend class KeyboardInput_Impl;
		friend class Thread_Impl;
		friend class Mutex_Impl;

		private:
			Engine();
			~Engine();
			void ManageResource(class EngineResource* mng_res, bool mng = true);

		public:
			void Delete();
			class Screen* CreateScreen(const char* title, int width, int height, bool fullscreen = false);
			class Thread* CreateThread(ThreadProc proc, void* data = NULL);
			class Mutex* CreateMutex();

		private:
			std::map<class EngineResource*, bool> res;
	};

	class Screen: public EngineResource
	{
		friend class Graphics_Impl;
		friend class Screen_Impl;

		private:
			Screen();
			Screen(Engine* eng, const char* title, int width, int height, bool fullscreen);
			virtual ~Screen();
			virtual void FreeGraphics() = 0;

		public:
			virtual void Delete() = 0;
			virtual void PumpEvents() = 0;
			virtual class Graphics* CreateGraphics(int cbits = 32, int zbits = 32, int sbits = 0, int abits = 0) = 0;
	};

	class Graphics: public EngineResource
	{
		friend class Graphics_Impl;

		private:
			Graphics();
			Graphics(	Screen* scr, int width, int height,
						int cbits, int zbits, int sbits, int abits, bool fullscreen);
			virtual ~Graphics();

		public:
			virtual void Delete() = 0;
			virtual void Present() = 0;
			virtual void Clear() = 0;
			virtual void ClearColor(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha) = 0;
			virtual void ClearStencil(int stencil) = 0;
			virtual void ClearAccum(float red, float green, float blue, float alpha) = 0;
			virtual void View2D() = 0;
			virtual void View3D() = 0;
			virtual void DrawPrimitive(PrimitiveType ptype, unsigned int vcount, const Vertex* verts) = 0;
	};

	class Thread: public EngineResource
	{
		friend class Thread_Impl;

		private:
			Thread();
			Thread(Engine* eng, ThreadProc proc, void* data);
			virtual ~Thread();

		public:
			virtual void Delete() = 0;
			virtual void Wait() = 0;
			virtual void Kill() = 0;
	};

	class Mutex: public EngineResource
	{
		friend class Mutex_Impl;

		private:
			Mutex();
			Mutex(Engine* eng);
			virtual ~Mutex();

		public:
			virtual void Delete() = 0;
			virtual void Lock() = 0;
			virtual void Unlock() = 0;
	};

	unsigned long long DME_EXPORT TimerValue();
}

#endif
